package com.example;

import io.minio.*;
import io.minio.errors.*;
import io.minio.messages.Bucket;
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.activation.MimetypesFileTypeMap;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.List;

import lombok.extern.slf4j.Slf4j;

@Component
@Slf4j
public class MinioService {

    @Value("${minio.url}")
    private String url;

    @Value("${minio.access-key}")
    private String accessKey;

    @Value("${minio.secret-key}")
    private String secretKey;


    /**
     * 初始化连接
     *
     * @return
     * @throws Exception
     */
    public MinioClient getMinioClient() {
        return MinioClient.builder().endpoint(url).credentials(accessKey, secretKey).build();
    }


    /**
     * 根据存储桶的名称判断桶是否存在，不存在就创建
     *
     * @param bucketName
     * @throws Exception
     */
    public void isExistBucketName(String bucketName) throws Exception {
        boolean isExist = getMinioClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build());
        if (!isExist) {
            getMinioClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
            log.info(bucketName + "创建成功");
        }
    }

    /**
     * Minio文本地文件上传
     *
     * @param filePath 完整路径文件名
     * @param fileName 修饰过的文件名 非源文件名
     * @return
     */
    public Results localMinioUpload(String filePath, String fileName, String bucketName) {
        try {
            //判断存储桶是否存在，不存在则创建
            isExistBucketName(bucketName);
            // minio仓库名
            File file = new File(filePath);
            InputStream is = new FileInputStream(file);
            String contentType = new MimetypesFileTypeMap().getContentType(file);
            System.out.println(contentType);
            getMinioClient().putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .stream(is,
                                    file.length(),
                                    -1)
                            .contentType(contentType)
                            .build());
            log.info("成功上传文件 " + fileName + " 至 " + bucketName);
            return Results.success(System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
            return Results.requestFailMsg(System.currentTimeMillis(), "上传存储服务器出错异常");
        }
    }


    /**
     * Minio远程文件上传 上传对象是MultipartFile
     *
     * @param file     文件实体
     * @param fileName 修饰过的文件名 非源文件名
     * @return
     */
    public Results minioUpload(MultipartFile file, String fileName, String bucketName) {
        try {
            //判断存储桶是否存在，不存在则创建
            isExistBucketName(bucketName);
            // fileName为空，说明要使用源文件名上传
            if (fileName == null) {
                fileName = file.getOriginalFilename();
                fileName = fileName.replaceAll(" ", "_");
            }
            getMinioClient().putObject(
                    PutObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .stream(file.getInputStream(),
                                    file.getSize(),
                                    -1)
                            .contentType(file.getContentType())
                            .build());
            log.info("成功上传文件 " + fileName + " 至 " + bucketName);
//            String fileUrl = bucketName + "/" + fileName;
//            Map<String, Object> map = new HashMap<String, Object>();
//            map.put("fileUrl", fileUrl);
//            map.put("bucketName", bucketName);
//            map.put("originFileName", fileName);
            return Results.success(System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
            return Results.requestFailMsg(System.currentTimeMillis(), "上传存储服务器出错异常");
        }
    }

    /**
     * 判断文件是否存在
     *
     * @param fileName   文件全路径
     * @param bucketName 存储桶名称
     * @return
     */
    public boolean isFileExisted(String fileName, String bucketName) {
        InputStream inputStream = null;
        try {
            inputStream = getMinioClient().getObject(
                    GetObjectArgs.builder()
                            .bucket(bucketName)
                            .object(fileName)
                            .build());
            if (inputStream != null) {
                return true;
            }
        } catch (Exception e) {
            return false;
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }


    /**
     * 删除文件
     *
     * @param bucketName 桶名（文件夹）
     * @param fileName   文件名
     * @return
     */
    public boolean delete(String bucketName, String fileName) {
        try {
            getMinioClient().removeObject(
                    RemoveObjectArgs.builder().bucket(bucketName).object(fileName).build());
            return true;
        } catch (Exception e) {
            log.error(e.getMessage());
            return false;
        }
    }


    /**
     * 获取文件的外链访问URL，并设置URL访问有效期
     *
     * @param fileName
     * @return
     * @throws Exception
     */
    public String getShowUtrl(String fileName, int expires, String bucketName) throws Exception {
        String tempUrl = getMinioClient().presignedGetObject(bucketName, fileName, expires);
        return tempUrl;
    }

    /**
     * 获取minio文件的下载地址
     *
     * @param bucketName
     * @param fileName
     * @return
     */
    @SneakyThrows(Exception.class)
    public String getFileUrl(String bucketName, String fileName) {
        return getMinioClient().presignedGetObject(bucketName, fileName);
    }

    /**
     * 获取全部bucket
     *
     * @param :
     * @return: java.util.List<io.minio.messages.Bucket>
     * @date :
     */
    @SneakyThrows(Exception.class)
    public List<Bucket> getAllBuckets() {
        return getMinioClient().listBuckets();
    }


    /**
     * 创建 bucket
     *
     * @param bucketName: 文件桶名
     * @return: void
     * @date :
     */
    @SneakyThrows(Exception.class)
    public void createBucket(String bucketName) {
        boolean isExist = getMinioClient().bucketExists(bucketName);
        if (!isExist) {
            getMinioClient().makeBucket(bucketName);
        }
    }

    /**
     * 下载文件
     *
     * @param bucketName: 文件桶名
     * @param fileName:   文件名
     * @param
     * @return: void
     * @date :
     */
    @SneakyThrows(Exception.class)
    public InputStream download(String bucketName, String fileName) {
        // 获取对象的元数据
        return getMinioClient().getObject(bucketName, fileName);
    }


    /**
     * 下载文件
     *
     * @param objectName 文件名
     * @param response
     * @return
     */
    public Results downloadFile(String objectName, HttpServletResponse response, String bucketName) {
        try {
            InputStream stream = getMinioClient().getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
            String filename = new String(objectName.getBytes("ISO8859-1"), StandardCharsets.UTF_8);
            response.setHeader("Content-Disposition", "attachment;filename=" + filename);
            ServletOutputStream servletOutputStream = response.getOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = stream.read(buffer)) > 0) {
                servletOutputStream.write(buffer, 0, len);
            }
            servletOutputStream.flush();
            stream.close();
            servletOutputStream.close();
            return Results.success(System.currentTimeMillis());
        } catch (Exception e) {
            e.printStackTrace();
            return Results.requestFailMsg(System.currentTimeMillis(), "下载报错异常！");
        }
    }


    public static void main(String[] args) throws Exception {
        MinioService ms = new MinioService();
        String strUrl = "D:/photo/1.jpg";
        ms.localMinioUpload(strUrl, "D:/photo/1.jpg", "test");
    }

}
